home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / DIConfig / cdevicecontrol.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  14.8 KB  |  616 lines

  1. //-----------------------------------------------------------------------------
  2. // File: cdevicecontrol.cpp
  3. //
  4. // Desc: CDeviceControl is a class that encapsulate the functionality of a
  5. //       device control (or a callout).  CDeviceView accesses it to retrieve/
  6. //       save information about the control.
  7. //
  8. // Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
  9. //-----------------------------------------------------------------------------
  10.  
  11. #include "common.hpp"
  12.  
  13.  
  14. CDeviceControl::CDeviceControl(CDeviceUI &ui, CDeviceView &view) :
  15.     m_ui(ui),
  16.     m_view(view),
  17.     m_bHighlight(FALSE),
  18.     m_ptszCaption(NULL),
  19.     m_dwDrawTextFlags(0),
  20.     m_FontHeight(-1),
  21.     m_bCalledCalcCallout(FALSE),
  22.     m_bPlacedOnlyFirstCorner(FALSE),
  23.     m_bInit(FALSE),
  24.     m_dwCalloutAlign(CAF_TOPLEFT),
  25.     m_nLinePoints(0),
  26.     m_dwDeviceControlOffset((DWORD)-1),
  27.     m_bOffsetAssigned(FALSE),
  28.     m_pbmOverlay(NULL),
  29.     m_pbmHitMask(NULL),
  30.     m_ptszOverlayPath(NULL),
  31.     m_bCaptionClipped(FALSE)
  32. {
  33. }
  34.  
  35. CDeviceControl::~CDeviceControl()
  36. {
  37.     DEVICEUINOTIFY uin;
  38.     uin.from = DEVUINFROM_CONTROL;
  39.     uin.control.pControl = (CDeviceControl *)this;
  40.     uin.msg = DEVUINM_ONCONTROLDESTROY;
  41.     m_ui.Notify(uin);
  42.     if (m_ptszCaption)
  43.         free(m_ptszCaption);
  44.     delete m_pbmOverlay;
  45.     delete m_ptszOverlayPath;
  46. }
  47.  
  48. void CDeviceControl::SetCaption(LPCTSTR tszCaption, BOOL bFixed)
  49. {
  50.     LPTSTR tszNewCaption = NULL;
  51.  
  52.     m_bFixed = bFixed;
  53.  
  54.     if (tszCaption != NULL)
  55.     {
  56.         tszNewCaption = _tcsdup(tszCaption);
  57.  
  58.         if (tszNewCaption == NULL)
  59.             return;
  60.     }
  61.  
  62.     free(m_ptszCaption);
  63.     m_ptszCaption = tszNewCaption;
  64.     tszNewCaption = NULL;
  65.  
  66.     CalcCallout();
  67.     Invalidate();
  68. }
  69.  
  70. LPCTSTR CDeviceControl::GetCaption()
  71. {
  72.     return (LPCTSTR)m_ptszCaption;
  73. }
  74.  
  75. BOOL CDeviceControl::HitControl(POINT point)
  76. {
  77.     return FALSE;
  78. }
  79.  
  80. DEVCTRLHITRESULT CDeviceControl::HitTest(POINT test)
  81. {
  82.     if (!m_bInit)
  83.         return DCHT_NOHIT;
  84.  
  85.     if (m_ui.InEditMode() &&
  86.             PtInRect(&m_rectCalloutMax, test))
  87.         return DCHT_MAXRECT;
  88.  
  89.     PrepCallout();
  90.  
  91.     if (PtInRect(&m_rectCallout, test))
  92.         return DCHT_CAPTION;
  93.  
  94.     if (HitControl(test))
  95.         return DCHT_CONTROL;
  96.  
  97.     return DCHT_NOHIT;
  98. }
  99.  
  100. void CDeviceControl::Init()
  101. {
  102.     m_uin.from = DEVUINFROM_CONTROL;
  103.     m_uin.control.pControl = this;
  104.  
  105.     CalcCallout();
  106.  
  107.     m_bInit = TRUE;
  108. }
  109.  
  110. // We will have to know the view's scrolling offset to adjust the tooltip's position.
  111. void CDeviceControl::OnMouseOver(POINT point)
  112. {
  113.     // Tooltip only if the callout text is clipped.
  114.     if (m_bCaptionClipped)
  115.     {
  116.         TOOLTIPINITPARAM ttip;
  117.         ttip.hWndParent = GetParent(m_view.m_hWnd);  // Parent is the page window.
  118.         ttip.iSBWidth = 0;
  119.         ttip.dwID = m_dwDeviceControlOffset;
  120.         ttip.hWndNotify = m_view.m_hWnd;
  121.         ttip.tszCaption = GetCaption();
  122.         CFlexToolTip::UpdateToolTipParam(ttip);
  123.     } else
  124.         CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
  125.  
  126.     m_uin.msg = DEVUINM_MOUSEOVER;
  127.     m_ui.Notify(m_uin);
  128. }
  129.  
  130. void CDeviceControl::OnClick(POINT point, BOOL bLeft, BOOL bDoubleClick)
  131. {
  132.  
  133.     // If this control is not assigned, and we are in view mode, we should not do anything (highlight).
  134.     if (!lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption) && !m_ui.m_uig.InEditMode())
  135.         return;
  136.  
  137.     m_uin.msg = bDoubleClick ? DEVUINM_DOUBLECLICK : DEVUINM_CLICK;
  138.     m_uin.click.bLeftButton = bLeft;
  139.     m_ui.Notify(m_uin);
  140. }
  141.  
  142. void CDeviceControl::Unpopulate()
  143. {
  144. }
  145.  
  146. void CDeviceControl::Highlight(BOOL bHighlight)
  147. {
  148.     if (m_bHighlight == bHighlight)
  149.         return;
  150.  
  151.     // If the callout text is the default text, no action is assigned, and we don't highlight it.
  152.     if (!lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption) && bHighlight && !m_ui.m_uig.InEditMode())
  153.         return;
  154.  
  155.     m_bHighlight = bHighlight;
  156.  
  157.     // If the view has scrolling enabled, we need to adjust the scroll
  158.     // bar position to make this callout visible.
  159.     if (bHighlight)
  160.         m_view.ScrollToMakeControlVisible(m_rectCalloutMax);
  161.  
  162.     CalcCallout();
  163.  
  164.     // We do not invalidate rectangle if we are unhighlighting.  Let CDeviceView handle that.
  165.     if (bHighlight) Invalidate();
  166. }
  167.  
  168. void CDeviceControl::GetInfo(GUID &rGuid, DWORD &rdwOffset)
  169. {
  170.     m_ui.GetDeviceInstanceGuid(rGuid);
  171.     rdwOffset = m_dwDeviceControlOffset;
  172. }
  173.  
  174. BOOL CDeviceControl::PrepCaption()
  175. {
  176.     if (m_ptszCaption != NULL)
  177.         return TRUE;
  178.     m_ptszCaption = _tcsdup(g_tszUnassignedControlCaption);
  179.     return m_ptszCaption != NULL;
  180. }
  181.  
  182. void CDeviceControl::PrepLinePoints()
  183. {
  184.     if (m_nLinePoints > 0)
  185.         return;
  186.     m_nLinePoints = 1;
  187.     POINT pt = {0, 0};
  188.     if (m_dwCalloutAlign & CAF_LEFT)
  189.         pt.x = m_rectCalloutMax.left;
  190.     if (m_dwCalloutAlign & CAF_RIGHT)
  191.         pt.x = m_rectCalloutMax.right - 1;
  192.     if (m_dwCalloutAlign & CAF_TOP)
  193.         pt.y = m_rectCalloutMax.top;
  194.     if (m_dwCalloutAlign & CAF_BOTTOM)
  195.         pt.y = m_rectCalloutMax.bottom - 1;
  196.     if (!(m_dwCalloutAlign & (CAF_LEFT | CAF_RIGHT)))
  197.         pt.x = (m_rectCalloutMax.left + m_rectCalloutMax.right - 1) / 2;
  198.     if (!(m_dwCalloutAlign & (CAF_BOTTOM | CAF_TOP)))
  199.         pt.y = (m_rectCalloutMax.top + m_rectCalloutMax.bottom - 1) / 2;
  200.     m_rgptLinePoint[0] = pt;
  201. }
  202.  
  203. void CDeviceControl::PrepCallout()
  204. {
  205.     if (m_bCalledCalcCallout)
  206.         return;
  207.     CalcCallout();
  208. }
  209.  
  210. void CDeviceControl::PrepFont()
  211. {
  212.     if (m_FontHeight != -1)
  213.         return;
  214.  
  215.     HDC hDC = CreateCompatibleDC(NULL);
  216.     if (hDC != NULL)
  217.     {
  218.         RECT rect = {0, 0, 500, 1};
  219.         {
  220.             CPaintHelper ph(m_ui.m_uig, hDC);
  221.             ph.SetFont(UIF_CALLOUT);
  222.             m_FontHeight = DrawText(hDC, _T("Testify"), -1, &rect, m_dwDrawTextFlags);
  223.         }
  224.         DeleteDC(hDC);
  225.     }
  226. }
  227.  
  228. void CDeviceControl::CalcCallout()
  229. {
  230.     m_bCalledCalcCallout = TRUE;
  231.  
  232.     RECT max = m_rectCalloutMax;
  233.     InflateRect(&max, -1, -1);
  234.     RECT rect = max;
  235.     rect.bottom = rect.top + 1;
  236.  
  237.     PrepFont();
  238.  
  239.     HDC hDC = CreateCompatibleDC(NULL);
  240.  
  241.     {
  242.         CPaintHelper ph(m_ui.m_uig, hDC);
  243.         ph.SetFont(UIF_CALLOUT);
  244.  
  245.         // We make sure the max rect height is at least same as the font requires.
  246.         m_dwDrawTextFlags = DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS | DT_EDITCONTROL;
  247.         RECT hrect = rect;
  248.         DrawText(hDC, m_ptszCaption, -1, &hrect, m_dwDrawTextFlags);
  249.         if (hrect.bottom > max.bottom) max.bottom = hrect.bottom;
  250.  
  251.         m_dwDrawTextFlags = DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS | DT_EDITCONTROL;
  252.  
  253.         // first, drawtext/calcrect into the temporary rect
  254.         if (!PrepCaption())
  255.         {
  256.             return;
  257.         }
  258.  
  259.         int th = DrawText(hDC, m_ptszCaption, -1, &rect, m_dwDrawTextFlags);
  260.  
  261.         m_bCaptionClipped = rect.bottom > max.bottom || rect.right > max.right;  // Set clipped flag.
  262.         
  263.         BOOL bSingleTextLine = th <= m_FontHeight;
  264.  
  265.         if (rect.right > max.right)
  266.         {
  267.             bSingleTextLine = TRUE;
  268.             rect.right = max.right;
  269.         }
  270.  
  271.         if (bSingleTextLine)
  272.             m_dwDrawTextFlags &= ~DT_WORDBREAK;
  273.  
  274.         m_dwDrawTextFlags &= ~DT_CALCRECT;
  275.  
  276.         RECT rect2 = rect;
  277.         if (rect2.bottom > max.bottom)
  278.             rect2.bottom = max.bottom;
  279.         th = DrawText(hDC, m_ptszCaption, -1, &rect2, m_dwDrawTextFlags);
  280.         int ith = (th / m_FontHeight) * m_FontHeight;
  281.         rect.bottom = rect.top + ith + 1;
  282.     }
  283.  
  284.     DeleteDC(hDC);
  285.     hDC = NULL;
  286.  
  287.     if (rect.bottom > max.bottom)
  288.         rect.bottom = max.bottom;
  289.  
  290.     assert(rect.right <= max.right);
  291.     assert(rect.bottom <= max.bottom);
  292.  
  293.     PrepLinePoints();
  294.     POINT adj = {0, 0};
  295.  
  296.     assert(rect.left == max.left);
  297.     assert(rect.top == max.top);
  298.  
  299.     int w = rect.right - rect.left;
  300.     int h = rect.bottom - rect.top;
  301.     int mw = max.right - max.left;
  302.     int mh = max.bottom - max.top;
  303.     int dw = mw - w, dh = mh - h;
  304.     int cx = mw / 2 + max.left, cy = mh / 2 + max.top;
  305.     int cl = cx - w / 2, ct = cy - h / 2;
  306.  
  307.     assert(dw >= 0);
  308.     assert(dh >= 0);
  309.  
  310.     if (m_dwCalloutAlign & CAF_RIGHT && rect.right < max.right)
  311.         adj.x = max.right - rect.right;
  312.     if (m_dwCalloutAlign & CAF_BOTTOM && rect.bottom < max.bottom)
  313.         adj.y = max.bottom - rect.bottom;
  314.     if (!(m_dwCalloutAlign & (CAF_RIGHT | CAF_LEFT)) && w < mw && rect.left != cl)
  315.         adj.x = cl - rect.left;
  316.     if (!(m_dwCalloutAlign & (CAF_BOTTOM | CAF_TOP)) && h < mh && rect.top != ct)
  317.         adj.y = ct - rect.top;
  318.  
  319.     OffsetRect(&rect, adj.x, adj.y);
  320.  
  321.     InflateRect(&rect, 1, 1);
  322.  
  323.     m_rectCallout = rect;
  324. }
  325.  
  326. BOOL CDeviceControl::DrawOverlay(HDC hDC)
  327. {
  328.     if (m_pbmOverlay == NULL)
  329.         return FALSE;
  330.  
  331.     return m_pbmOverlay->Blend(hDC, m_ptOverlay);
  332. }
  333.  
  334. void CDeviceControl::OnPaint(HDC hDC)
  335. {
  336.     if (!m_bInit)
  337.         return;
  338.  
  339.     // If we are in view mode and the callout is not assigned, don't draw anything.
  340.     if (!m_ui.m_uig.InEditMode() && !lstrcmp(m_ptszCaption, g_tszUnassignedControlCaption))
  341.         return;
  342.  
  343.     PrepCallout();
  344.  
  345.     CPaintHelper ph(m_ui.m_uig, hDC);
  346.     UIELEMENT eCallout = m_bHighlight ? UIE_CALLOUTHIGH : UIE_CALLOUT;
  347.  
  348.     // draw lines...
  349.     if (m_nLinePoints > 1)
  350.     {
  351.         ph.SetElement(UIE_CALLOUTSHADOW);
  352.         PolyLineArrowShadow(hDC, m_rgptLinePoint, m_nLinePoints);
  353.         ph.SetElement(eCallout);
  354.         PolyLineArrow(hDC, m_rgptLinePoint, m_nLinePoints);
  355.     }
  356.  
  357.     // draw text
  358.     ph.SetElement(eCallout);
  359.     RECT rect = m_rectCallout;
  360.     InflateRect(&rect, -1, -1);
  361.  
  362.     // If this control is assigned an action with DIA_FIXED (m_bFixed), use gray color for text.
  363.     COLORREF OldColor;
  364.     if (m_bFixed)
  365.     {
  366.         OldColor = ::SetTextColor(hDC, 0);  // Set an arbitrary color to find out what we are currently using.
  367.         ::SetTextColor(hDC, RGB(GetRValue(OldColor) >> 1, GetGValue(OldColor) >> 1, GetBValue(OldColor) >> 1));
  368.     }
  369.  
  370.     if (m_ptszCaption)
  371.         DrawText(hDC, m_ptszCaption, -1, &rect, m_dwDrawTextFlags);
  372.  
  373.     if (m_bFixed)
  374.         ::SetTextColor(hDC, OldColor);
  375. }
  376.  
  377. void CDeviceControl::Invalidate()
  378. {
  379.     m_view.Invalidate();
  380. }
  381.  
  382. void MakeRect(RECT &rect, POINT a, POINT b)
  383. {
  384.     rect.left = min(a.x, b.x);
  385.     rect.right = max(a.x, b.x);
  386.     rect.top = min(a.y, b.y);
  387.     rect.bottom = max(a.y, b.y);
  388. }
  389.  
  390. void CDeviceControl::PlaceCalloutMaxCorner(int nCorner, POINT point)
  391. {
  392.     switch (nCorner)
  393.     {
  394.         case 0:
  395.             m_ptFirstCorner = point;
  396.             m_bPlacedOnlyFirstCorner = TRUE;
  397.             Invalidate();
  398.             break;
  399.  
  400.         case 1:
  401.             MakeRect(m_rectCalloutMax, m_ptFirstCorner, point);
  402.             m_bPlacedOnlyFirstCorner = FALSE;
  403.             if (!m_bInit)
  404.                 Init();
  405.             else
  406.                 CalcCallout();
  407.             Invalidate();
  408.             break;
  409.  
  410.         default:
  411.             assert(0);
  412.             break;
  413.     }
  414. }
  415.  
  416. void CDeviceControl::SetLastLinePoint(int nPoint, POINT point, BOOL bShiftDown)
  417. {
  418.     if (!(nPoint >= 0 && nPoint < MAX_DEVICECONTROL_LINEPOINTS))
  419.         return;
  420.  
  421.     // Check for SHIFT key state
  422.     if (nPoint && bShiftDown)  // SHIFT key only makes a difference if we are setting 2nd and subsequent points.
  423.     {
  424.         // SHIFT key down.  Need to draw controlled line.
  425.         if (labs(m_rgptLinePoint[nPoint-1].x - point.x) > labs(m_rgptLinePoint[nPoint-1].y - point.y))
  426.         {
  427.             // Wider. Draw horizontal.
  428.             m_rgptLinePoint[nPoint].x = point.x;
  429.             m_rgptLinePoint[nPoint].y = m_rgptLinePoint[nPoint-1].y;
  430.         } else
  431.         {
  432.             // Taller. Draw vertical
  433.             m_rgptLinePoint[nPoint].x = m_rgptLinePoint[nPoint-1].x;
  434.             m_rgptLinePoint[nPoint].y = point.y;
  435.         }
  436.     } else
  437.         m_rgptLinePoint[nPoint] = point; // SHIFT key not down.  Draw line as usual.
  438.     m_nLinePoints = nPoint + 1;
  439.     Invalidate();
  440.  
  441.     if (m_nLinePoints < 2)
  442.         return;
  443.  
  444.     POINT prev = m_rgptLinePoint[m_nLinePoints - 2];
  445.  
  446.     // remove identical points
  447.     if (point.x == prev.x && point.y == prev.y)
  448.     {
  449.         m_nLinePoints--;
  450.         return;
  451.     }
  452. }
  453.  
  454. void PlaceRectCenter(RECT &rect, POINT point)
  455. {
  456.     POINT center = {
  457.         (rect.left + rect.right) / 2,
  458.         (rect.top + rect.bottom) / 2};
  459.  
  460.     OffsetRect(&rect, point.x - center.x, point.y - center.y);
  461. }
  462.  
  463. void OffsetRectToWithin(RECT &rect, const RECT &bounds)
  464. {
  465.     POINT adj = {0, 0};
  466.  
  467.     if (rect.left < bounds.left)
  468.         adj.x = bounds.left - rect.left;
  469.     if (rect.right > bounds.right)
  470.         adj.x = bounds.right - rect.right;
  471.     if (rect.top < bounds.top)
  472.         adj.y = bounds.top - rect.top;
  473.     if (rect.bottom > bounds.bottom)
  474.         adj.y = bounds.bottom - rect.bottom;
  475.  
  476.     OffsetRect(&rect, adj.x, adj.y);
  477. }
  478.  
  479. void CDeviceControl::Position(POINT point)
  480. {
  481.     PlaceRectCenter(m_rectCalloutMax, point);
  482.     RECT client;
  483.     m_view.GetClientRect(&client);
  484.     OffsetRectToWithin(m_rectCalloutMax, client);
  485.     CalcCallout();
  486.     Invalidate();
  487. }
  488.  
  489. void CDeviceControl::ConsiderAlignment(POINT point)
  490. {
  491.     POINT center = {
  492.         (m_rectCalloutMax.right + m_rectCalloutMax.left) / 2,
  493.         (m_rectCalloutMax.bottom + m_rectCalloutMax.top) / 2};
  494.     SIZE dim = {
  495.         m_rectCalloutMax.right - m_rectCalloutMax.left,
  496.         m_rectCalloutMax.bottom - m_rectCalloutMax.top};
  497.     SIZE delta = {point.x - center.x, point.y - center.y};
  498.     int MININ = m_FontHeight;
  499.     SIZE in = {max(dim.cx / 4, MININ), max(dim.cy / 4, MININ)};
  500.     DWORD align = 0;
  501.     if (delta.cx < -in.cx)
  502.         align |= CAF_LEFT;
  503.     if (delta.cx > in.cx)
  504.         align |= CAF_RIGHT;
  505.     if (delta.cy < -in.cy)
  506.         align |= CAF_TOP;
  507.     if (delta.cy > in.cy)
  508.         align |= CAF_BOTTOM;
  509.     m_dwCalloutAlign = align;
  510.     CalcCallout();
  511.     Invalidate();
  512. }
  513.  
  514. DWORD CDeviceControl::GetOffset()
  515. {
  516.     if (m_bOffsetAssigned)
  517.         return m_dwDeviceControlOffset;
  518.  
  519.     return (DWORD)-1;
  520. }
  521.  
  522. BOOL CDeviceControl::IsOffsetAssigned()
  523. {
  524.     return m_bOffsetAssigned;
  525. }
  526.  
  527. void CDeviceControl::FillImageInfo(DIDEVICEIMAGEINFOW *pImgInfo)
  528. {
  529.     if (!pImgInfo) return;
  530.  
  531.     if (m_ptszOverlayPath != NULL)
  532.         CopyStr(pImgInfo->tszImagePath, m_ptszOverlayPath, MAX_PATH);
  533.     else
  534.         wcscpy(pImgInfo->tszImagePath, L"");  // Overlay Image not yet supported
  535.  
  536.     SIZE size = {0, 0};
  537.     if (m_pbmOverlay != NULL)
  538.         m_pbmOverlay->GetSize(&size);
  539.     RECT rect = {m_ptOverlay.x, m_ptOverlay.y,
  540.         m_ptOverlay.x + size.cx, m_ptOverlay.y + size.cy};
  541.  
  542.     pImgInfo->dwFlags = DIDIFT_OVERLAY;  // This is an overlay
  543.     pImgInfo->rcOverlay = rect;
  544.     pImgInfo->dwObjID = GetOffset();
  545.     pImgInfo->dwcValidPts = m_nLinePoints;
  546.     DWORD dwPtsToCopy = m_nLinePoints > 5 ? 5 : m_nLinePoints;
  547.     for (DWORD i = 0; i < dwPtsToCopy; ++i)
  548.         pImgInfo->rgptCalloutLine[i] = m_rgptLinePoint[i];
  549.     pImgInfo->rcCalloutRect = m_rectCalloutMax;
  550.     pImgInfo->dwTextAlign = m_dwCalloutAlign;
  551. }
  552.  
  553.  
  554. BOOL CDeviceControl::IsMapped()
  555. {
  556.     return m_ui.IsControlMapped(this);
  557. }
  558.  
  559. int CDeviceControl::GetControlIndex()
  560. {
  561.     for (int i = 0; i < m_view.GetNumControls(); i++)
  562.         if (m_view.GetControl(i) == this)
  563.             return i;
  564.  
  565.     return -1;
  566. }
  567.  
  568. void CDeviceControl::SetLinePoints(int n, POINT *rgpt)
  569. {
  570.     assert(n >= 0 && n <= MAX_DEVICECONTROL_LINEPOINTS && rgpt);
  571.  
  572.     if (n < 0)
  573.         n = 0;
  574.     if (n > MAX_DEVICECONTROL_LINEPOINTS)
  575.         n = MAX_DEVICECONTROL_LINEPOINTS;
  576.  
  577.     if (!rgpt)
  578.         n = 0;
  579.  
  580.     m_nLinePoints = n;
  581.  
  582.     for (int i = 0; i < n; i++)
  583.         m_rgptLinePoint[i] = rgpt[i];
  584. }
  585.  
  586. void CDeviceControl::SetOverlayPath(LPCTSTR tszPath)
  587. {
  588.     if (m_ptszOverlayPath)
  589.         free(m_ptszOverlayPath);
  590.     m_ptszOverlayPath = NULL;
  591.  
  592.     if (tszPath)
  593.         m_ptszOverlayPath = _tcsdup(tszPath);
  594.  
  595.     delete m_pbmOverlay;
  596.     m_pbmOverlay = NULL;
  597.  
  598.     if (m_ptszOverlayPath)
  599.     {
  600.         LPDIRECT3DSURFACE8 pSurf = m_ui.m_uig.GetSurface3D();  // GetSurface3D() calls AddRef() on the surface.
  601.         m_pbmOverlay = CBitmap::CreateViaD3DX(m_ptszOverlayPath, pSurf);
  602.         if (pSurf)
  603.         {
  604.             // Release surface instance after we are done with it so we don't leak memory.
  605.             pSurf->Release();
  606.             pSurf = NULL;
  607.         }
  608.     }
  609. }
  610.  
  611. void CDeviceControl::SetOverlayRect(const RECT &r)
  612. {
  613.     m_ptOverlay.x = r.left;
  614.     m_ptOverlay.y = r.top;
  615. }
  616.